local hotkeys = {
	START_BOT = {key = _G.key.VK_DELETE, modifier = nil},
	STOP_BOT = {key = _G.key.VK_END, modifier = nil},
}


ON = "|lightgreen|on "
OFF = "|lightred|off"

local charUpdatePattern = string.char(0x85, 0xED, 0x0F, 0x84, 0xFF, 0xFF, 0xFF, 0xFF, 0x8B, 0x45, 0x00,
	0x8B, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0x50, 0xE8);
local charUpdateMask = "xxxx????xxxxx????xx";
local charUpdateOffset = 13;

local macroUpdatePattern = string.char(0xFF, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x8B, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8);
local macroUpdateMask = "xx????xx????x";
local macroUpdateOffset = 8;

local romMouseRClickFlag = 0x8000;
local romMouseLClickFlag = 0x80;

function getCharUpdatePattern()
	return charUpdatePattern;
end

function getCharUpdateMask()
	return charUpdateMask;
end

function getCharUpdateOffset()
	return charUpdateOffset;
end

function getMacroUpdatePattern()
	return macroUpdatePattern;
end

function getMacroUpdateMask()
	return macroUpdateMask;
end

function getMacroUpdateOffset()
	return macroUpdateOffset;
end

function checkExecutableCompatible()
	if( findPatternInProcess(getProc(), charUpdatePattern, charUpdateMask,
	addresses.staticpattern_char, 1) == 0 ) then
		return false;
	end

	if( findPatternInProcess(getProc(), macroUpdatePattern, macroUpdateMask,
	addresses.staticpattern_macro, 1) == 0 ) then
		return false;
	end

	return true;
end

-- Ask witch character does the user want to be, from the open windows.
function selectGame(character)
	-- Get list of windows in an array
	local windowList = findWindowList("*", "Radiant Arcana");

	if( #windowList == 0 ) then
		print("You need to run rom first!");
		return 0;
	end

	charToUse = {};
	for i = 1, #windowList, 1 do
		local process, playerAddress, nameAddress;
	    -- open first window
		process = openProcess(findProcessByWindow(windowList[i]));
		-- read player address
		showWarnings(false);
		if addresses["staticbase_char"] and addresses["charPtr_offset"] and addresses["pawnName_offset"] then
			playerAddress = memoryReadUIntPtr(process, addresses["staticbase_char"], addresses["charPtr_offset"]);
			-- read player name
			if( playerAddress ) then
				nameAddress = memoryReadUInt(process, playerAddress + addresses["pawnName_offset"]);
			end
		end
		-- store the player name, with window number
		if nameAddress == nil then
		    charToUse[i] = "(RoM window "..i..")";
  		else
			charToUse[i] = memoryReadString(process, nameAddress);
		end
		showWarnings(true);
		closeProcess(process);
	end

	if( character ) then
		for i,v in pairs(charToUse) do
			printf("[DEBUG] char: '%s', win: %s\n", tostring(v), tostring(windowList[i]));
			if( string.lower(v) == string.lower(character) ) then
				return windowList[i];
			end
		end
	end

	windowChoice = 1;
	-- wait until enter is released
    while keyPressedLocal(key.VK_RETURN) do
    	yrest(200);
    end

    notShown = true;
	if (#windowList > 1) then  -- if theres more than 1 window, ask the player witch character to use
		while not keyPressedLocal(key.VK_RETURN) do
	    	if keyPressedLocal(key.VK_UP) or keyPressedLocal(key.VK_DOWN) or notShown then
	        	notShown = false;
	    		if keyPressedLocal(key.VK_DOWN) then
	        		windowChoice = windowChoice + 1;
	        		if windowChoice > #charToUse then
	        	    	windowChoice = #charToUse;
					end
	    		end
	    		if keyPressedLocal(key.VK_UP) then
	        		windowChoice = windowChoice - 1;
	        		if windowChoice < 1 then
	        	    	windowChoice = 1;
					end
	    		end

				if keyPressedLocal(key.VK_UP) or keyPressedLocal(key.VK_DOWN) then
					print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
				end

				-- start message
	    		printf("Choose your character that you want to play on:\n");

	    		for i = 1, #charToUse, 1 do
	        		if i == windowChoice then
	    				cprintf(240, "\n"..charToUse[i]);
					else
	    				printf("\n"..charToUse[i]);
					end
				end
				printf("\n");
				yrest(200);
	    	end
	    	if keyPressedLocal(hotkeys.STOP_BOT.key) then
	        	error("User quit");
			end
		end
		yrest(200)
	end

	return windowList[windowChoice];
end

function getWin(character)
	if( __WIN == nil ) then
  		__WIN = selectGame(character);
	end

	return __WIN;
end

function getProc()
	if( __PROC == nil or not windowValid(__WIN) ) then
		if( __PROC ) then closeProcess(__PROC) end;
		__PROC = openProcess( findProcessByWindow(getWin()) );
	end

	return __PROC;
end

function keyComboPressed(_key)
	if _key and keyPressedLocal(_key.key) then
		if _key.modifier == nil or keyPressedLocal(_key.modifier) then
			return true
		end
	end
end

--==  SWIM FUNTIONS  ==--

local swimoffsets = {addresses.charPtr_offset, addresses.pawnSwim_offset1, addresses.pawnSwim_offset2}
local swimactive = 4

function flyon()
	memoryWriteString(getProc(), addresses.swimAddress, string.rep(string.char(0x90),#addresses.swimAddressBytes));
	memoryWriteIntPtr(getProc(), addresses.staticbase_char, swimoffsets, swimactive);
end

function flyoff()
	memoryWriteString(getProc(), addresses.swimAddress, string.char(unpack(addresses.swimAddressBytes)));
end

function flytoggle()
	if memoryReadIntPtr(getProc(), addresses.staticbase_char, swimoffsets) == swimactive then
		flyoff()
		return OFF
	else
		flyon()
		return ON
	end
end

--== WALL FUNCTIONS  ==--

local whacked = 0.2;
local wnormal = 4;

function wallon()
	memoryWriteFloat(getProc(), addresses.wallAddress, whacked);
end

function walloff()
	memoryWriteFloat(getProc(), addresses.wallAddress, wnormal);
end

function walltoggle()
	local var =	 memoryReadFloat(getProc(), addresses.wallAddress)
	var = tonumber(string.sub(var,1,3))
	if var == whacked then
		walloff()
		return OFF
	else
		wallon()
		return ON
	end
end

--==  SPEED FUNCTIONS  ==--

function setSpeed(speed)
	local playerAddress = memoryReadIntPtr(getProc(), addresses.staticbase_char, addresses.charPtr_offset) or 0
	if playerAddress ~= 0 then
		memoryWriteFloat(getProc(), playerAddress + addresses.speedOffset, speed);
	end
end

function getSpeed()
	local playerAddress = memoryReadIntPtr(getProc(), addresses.staticbase_char, addresses.charPtr_offset) or 0
	if playerAddress ~= 0 then
		return memoryReadFloat(getProc(), playerAddress + addresses.speedOffset)
	end
end

function speedup()
	local speed = getSpeed()
	if speed and speed < maximum_speed then
		speed = speed + speed_increments
		if speed > maximum_speed then speed = maximum_speed end
		setSpeed(speed)
		return speed
	end
end

function speeddown()
	local speed = getSpeed()
	if speed and speed > minimum_speed then
		speed = speed - speed_increments
		if speed < minimum_speed then speed = minimum_speed end
		setSpeed(speed)
		return speed
	end
end

function speedtoggle(enabled, setvalue)
	if enabled then
		setSpeed(normal_speed)
	else
		setSpeed(setvalue)
	end
end

